#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>
#include <thread>
#include <vector>

using namespace std;

#define NUM 5

int g_val = 700;

class threadData {
 public:
  threadData(const int number, pthread_mutex_t *mutex) : lock_(mutex) {
    threadname_ = "Thread_" + to_string(number);
  }

 public:
  string threadname_;
  pthread_t tid_;
  pthread_mutex_t *lock_;
  // 在类中定义一个互斥锁对象类型指针用于接收在主线程中实例化的锁
};

void *threadRoutine(void *args) {
  threadData *td = static_cast<threadData *>(args);

  td->tid_ = pthread_self();
  while (true) {
    pthread_mutex_lock(td->lock_);  // 锁定互斥锁对象
    if (g_val > 0) {
      usleep(100);
      printf("I am %s , the g_val = %3d\n", td->threadname_.c_str(), g_val);
      g_val--;

      pthread_mutex_unlock(td->lock_);  // 解锁互斥锁对象

    } else {
      pthread_mutex_unlock(td->lock_);  // 解锁互斥锁对象
      /*
      当一个线程锁定了一个锁时必须经过 if 或者 else 两个选项之一
      为了避免带锁的线程未在 else 处解锁而退出所导致死锁问题
      应在 if else 两处都进行解锁
      */

      break;
    }
    usleep(50);
  }
  delete td;  // 线程退出时释放描述自身基本属性的结构体对象
  return nullptr;
}

int main() {
  vector<pthread_t> tids;

  pthread_mutex_t lock;                // 定义一个互斥锁对象
  pthread_mutex_init(&lock, nullptr);  // 初始化该互斥锁对象

  for (size_t i = 0; i < NUM; ++i) {
    pthread_t tid;
    threadData *td = new threadData(i, &lock);
    pthread_create(&tid, nullptr, threadRoutine, td);
    // (传入互斥锁对象的指针)利用 new 实例化一个用来维护线程的结构体对象
    // 并将该实例化的对象传给线程作为参数

    tids.push_back(tid);
  }

  for (size_t i = 0; i < tids.size(); ++i) {
    pthread_join(tids[i], nullptr);
  }
  pthread_mutex_destroy(&lock);  // 销毁互斥锁对象
  return 0;
}
